<template>
  <div>
    <SearchForm
        @search="onSearch"
        @reset="onReset"
        :search-list="searchList" :search-params="searchParams">

      <template v-slot:button>
        <el-button type="primary" size="mini" icon="el-icon-upload" @click="showUploadDialog">上传文件</el-button>
      </template>
    </SearchForm>

    <div class="file-layout">
      <el-card shadow="never">

        <div class="file-grid" v-loading="loading">
          <template v-if="tableData.length > 0">
            <div
              v-for="file in tableData"
              :key="file.id"
              class="file-item"
              :class="{'file-selected': selectable && isSelected(file)}"
              @click="selectable && selectFile(file)"
            >
              <!-- 图片文件 -->
              <div v-if="isImageFile(file.file_type)" class="file-preview">
                <el-image
                  :src="file.file_url"
                  fit="cover"
                  :preview-src-list="[file.file_url]"
                ></el-image>
              </div>

              <!-- 音频文件 -->
              <div v-else-if="isAudioFile(file.file_type)" class="file-preview audio-preview">
                <i class="el-icon-headset"></i>
                <audio :src="file.file_url" controls class="audio-player"></audio>
              </div>

              <!-- 视频文件 -->
              <div v-else-if="isVideoFile(file.file_type)" class="file-preview video-preview">
                <i class="el-icon-video-camera"></i>
                <video :src="file.file_url" controls class="video-player"></video>
              </div>

              <!-- 其他文件 -->
              <div v-else class="file-preview other-preview">
                <i class="el-icon-document"></i>
              </div>

              <div class="file-info">
                <div class="file-name" :title="file.file_origin_name">{{ truncateFilename(file.file_origin_name) }}</div>
                <div class="file-meta">
                  <span>{{ formatFileSize(file.file_size) }}</span>
                  <span>{{ formatDate(file.create_time) }}</span>
                </div>
                <div class="file-actions">
                  <el-tooltip content="复制链接" placement="top">
                    <i class="el-icon-copy-document" @click="copyFileUrl(file.file_url)"></i>
                  </el-tooltip>
                  <el-tooltip content="下载" placement="top">
                    <a :href="file.file_url" target="_blank" download><i class="el-icon-download"></i></a>
                  </el-tooltip>
                  <el-tooltip content="删除" placement="top">
                    <i class="el-icon-delete" @click="onDelete(file)"></i>
                  </el-tooltip>
                </div>
              </div>
            </div>
          </template>

          <div v-if="tableData.length === 0 && !loading" class="no-files">
            <i class="el-icon-folder-opened"></i>
            <p>没有文件</p>
          </div>
        </div>
      </el-card>

      <div class="page-box">
        <el-pagination
            background
            :current-page="pageNo"
            :page-sizes="pageSizes"
            :page-size="pageSize"
            layout="total, sizes, prev, pager, next, jumper"
            :total="totalSize"
            @size-change="changePageSize"
            @current-change="changePageNo"
        />
      </div>
    </div>

    <!-- 上传文件对话框 -->
    <el-dialog
      title="上传文件"
      :append-to-body="true"
      :visible.sync="uploadDialogVisible"
      width="500px"
      :close-on-click-modal="false"
    >
      <el-upload
        v-if="uploadDialogVisible"
        class="upload-container"
        drag
        action=""
        :http-request="handleFileUpload"
        :before-upload="beforeUpload"
        :limit="1"
        :show-file-list="true"
      >
        <i class="el-icon-upload"></i>
        <div class="el-upload__text">将文件拖到此处，或<em>点击上传</em></div>
<!--        <div class="el-upload__tip" slot="tip">支持任意类型的文件，单个文件不超过 50MB</div>-->
      </el-upload>

      <span slot="footer" class="dialog-footer">
        <el-button @click="uploadDialogVisible = false">取 消</el-button>
      </span>
    </el-dialog>
  </div>
</template>
<script>
import crud from "@/mixins/crud";
import { http, uploadFile } from "@/api";
import dayjs from 'dayjs';

export default {
  name: "file",
  mixins: [crud],
  props: {
    selectable: {
      type: Boolean,
      default: false
    },
    multiple: {
      type: Boolean,
      default: false
    },
    selectedFiles: {
      type: Array,
      default: () => []
    }
  },
  data() {
    return {
      request: http.file,
      uploadDialogVisible: false,
      searchList: [
        {
          prop: 'file_origin_name',
          label: '文件名称',
          name: 'input',
          placeholder: '文件名称'
        },
      ],
      searchParams: {
        file_origin_name: '',
      },
      loading: false,
      pageNo: 1,
      pageSize: 10,
      pageSizes: [10, 20, 30, 40, 50],
      totalSize: 0,
      tableData: [],
      // 内部选中的文件列表
      internalSelectedFiles: []
    }
  },
  created() {
    // 初始化内部选中的文件列表
    if (this.selectedFiles && this.selectedFiles.length > 0) {
      this.internalSelectedFiles = [...this.selectedFiles];
    }
  },
  methods: {
    // 文件类型判断
    isImageFile(type) {
      return type && (type.startsWith('image/') || type === 'image');
    },
    isAudioFile(type) {
      return type && (type.startsWith('audio/') || type === 'audio');
    },
    isVideoFile(type) {
      return type && (type.startsWith('video/') || type === 'video');
    },

    // 格式化文件大小
    formatFileSize(bytes) {
      if (!bytes || bytes === 0) return '0 B';
      const k = 1024;
      const sizes = ['B', 'KB', 'MB', 'GB'];
      const i = Math.floor(Math.log(bytes) / Math.log(k));
      return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i];
    },

    // 格式化日期
    formatDate(date) {
      return dayjs(date).format('YYYY-MM-DD');
    },

    // 截断文件名
    truncateFilename(filename) {
      if (!filename) return '';
      if (filename.length <= 15) return filename;
      const ext = filename.lastIndexOf('.') > 0 ? filename.substring(filename.lastIndexOf('.')) : '';
      const name = filename.substring(0, filename.length - ext.length);
      return name.substring(0, 10) + '...' + (ext ? ext : '');
    },

    // 复制文件URL
    copyFileUrl(url) {
      const input = document.createElement('input');
      input.setAttribute('value', url);
      document.body.appendChild(input);
      input.select();
      document.execCommand('copy');
      document.body.removeChild(input);
      this.$message.success('链接已复制到剪贴板');
    },

    // 显示上传对话框
    showUploadDialog() {
      this.uploadDialogVisible = true;
    },

    // 上传前验证
    beforeUpload(file) {
      // const maxSize = 50 * 1024 * 1024; // 50MB
      // if (file.size > maxSize) {
      //   this.$message.error('文件大小不能超过 50MB');
      //   return false;
      // }
      return true;
    },

    // 处理文件上传
    async handleFileUpload({ file }) {
      try {
        const response = await uploadFile(file);
        if (response && response.data) {
          this.$message.success('文件上传成功');
          this.uploadDialogVisible = false;
          this.initData(); // 重新加载文件列表
        }
      } catch (error) {
        console.error('上传失败:', error);
        this.$message.error('文件上传失败: ' + (error.message || '未知错误'));
      }
    },

    // 文件选择相关方法
    selectFile(file) {
      if (this.multiple) {
        // 多选模式
        const index = this.internalSelectedFiles.findIndex(f => f.id === file.id);
        if (index > -1) {
          // 如果已经选中，则取消选择
          this.internalSelectedFiles.splice(index, 1);
        } else {
          // 否则添加到选中列表
          this.internalSelectedFiles.push(file);
        }
      } else {
        // 单选模式
        this.internalSelectedFiles = [file];
      }

      // 触发选择事件
      this.$emit('file-selected', this.internalSelectedFiles);
    },

    // 判断文件是否被选中
    isSelected(file) {
      return this.internalSelectedFiles.some(f => f.id === file.id);
    },

    // 获取选中的文件列表
    getSelectedFiles() {
      return this.internalSelectedFiles;
    },
  }
}
</script>

<style scoped lang="scss">
.file-layout {
  margin-top: 20px;
}

.file-handle {
  margin-bottom: 20px;
  display: flex;
  justify-content: flex-start;
  gap: 10px;
  align-items: center;

  .selection-tip {
    margin-left: auto;
    color: #909399;
    font-size: 13px;
  }
}

.file-grid {
  display: flex;
  flex-wrap: wrap;
  gap: 15px;
  min-height: 300px;
}

.file-item {
  width: 150px;
  height: 180px;
  border-radius: 4px;
  border: 1px solid #ebeef5;
  overflow: hidden;
  transition: all 0.3s;
  position: relative;
  background-color: #fff;
  box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.05);

  &:hover {
    transform: translateY(-3px);
    box-shadow: 0 5px 15px rgba(0, 0, 0, 0.1);

    .file-actions {
      opacity: 1;
    }
  }

  &.file-selected {
    border: 2px solid #409EFF;
    transform: translateY(-3px);
    box-shadow: 0 5px 15px rgba(0, 0, 0, 0.1);

    &:after {
      content: '✓';
      position: absolute;
      top: 4px;
      right: 4px;
      width: 16px;
      height: 16px;
      background-color: #409EFF;
      color: white;
      border-radius: 50%;
      display: flex;
      align-items: center;
      justify-content: center;
      font-size: 10px;
      z-index: 10;
    }
  }
}

.file-preview {
  height: 120px;
  display: flex;
  align-items: center;
  justify-content: center;
  background-color: #f5f7fa;
  overflow: hidden;

  .el-image {
    width: 100%;
    height: 100%;
    object-fit: cover;
  }

  i {
    font-size: 40px;
    color: #909399;
  }
}

.audio-preview, .video-preview, .other-preview {
  flex-direction: column;
  gap: 10px;
}

.audio-player, .video-player {
  width: 130px;
  height: 30px;
  margin-top: 8px;
}

.file-info {
  padding: 10px;
  position: relative;
}

.file-name {
  font-size: 13px;
  margin-bottom: 4px;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.file-meta {
  display: flex;
  justify-content: space-between;
  font-size: 12px;
  color: #909399;
}

.file-actions {
  position: absolute;
  top: 0;
  right: 0;
  display: flex;
  gap: 10px;
  padding: 5px;
  background-color: rgba(255, 255, 255, 0.9);
  border-radius: 4px;
  opacity: 0;
  transition: opacity 0.3s;

  i {
    cursor: pointer;
    font-size: 16px;
    color: #606266;

    &:hover {
      color: #409EFF;
    }
  }

  .el-icon-delete:hover {
    color: #F56C6C;
  }
}

.no-files {
  width: 100%;
  height: 300px;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  color: #909399;

  i {
    font-size: 60px;
    margin-bottom: 20px;
  }

  p {
    font-size: 16px;
  }
}

.upload-container {
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: center;
  width: 100%;
}

.page-box {
  margin-top: 20px;
  text-align: right;
}
</style>
